import threading
import time
import MetaTrader5 as mt5
from utils.e_mail import sendMail
from control.order_control import Order, OrderType
from constant.globl_constant import eventTag, signalTag, callbackTag, immediatelyTag
import constant.param_config as config
from worker.base.base_worker import BaseWorker
from utils.log_util import prints, saveLog
from utils.time_util import current_time
from constant.globl_constant import fibList2


class OrderWorker(BaseWorker):

    orderCheckNotice = 0
    printLog = False

    def __init__(self):
        super().__init__()

    def startThread(self):
        thread = threading.Thread(target=self.execution)
        # thread.daemon = True  # 设置线程为守护线程，以便在主程序退出时自动结束线程
        thread.start()

    def execution(self):
        """
        检测订单盈利状态
        """
        prints("订单检测服务已启动...")

        while True:
            if self.isLogin and self.marketClose() is False:
                self.lossAndPofit()

                # 加仓
                self.addOrder()
            time.sleep(0.5)

    def lossAndPofit(self):
        """
        订单盈利状况
        """

        total = self.getPositionsDetail(symbol=self.symble)
        if total is None or len(total) == 0:
            return

        if self.orderCheckNotice == 0 or current_time(
        ) - self.orderCheckNotice > 10:
            saveLog("订单状态检测中...")
            self.orderCheckNotice = current_time()

        # 在重要事件公布前后一段时间内禁止下单，或关闭非事件订单
        if BaseWorker.forbidDeal:
            total = self.forbidAgo(total)
            # 重要事件是否公布
            if BaseWorker.eventShow is False or len(total) == 0:
                return

        # 订单超时处理
        self.orderTimeOut(total)

        # 达到目标盈利或者到达阻力位时，关闭订单，只处理信号单和回调单
        self.tagerClose()

        # 止损，只处理信号单
        self.toTargetClose()

        # 移动止盈，所有类型订单
        self.move2Profit()

    def forbidAgo(self, total):
        """
        将要公布重要数据时，关闭盈利的非数据单
        """
        orderList = []
        for item in total:
            profit = item.profit
            if eventTag not in item.comment:
                if profit > 0.2:
                    self.control.closeOrder(item)
            else:
                orderList.append(item)
        return orderList

    def move2Profit(self):
        """
        移动止损
        """

        total = self.getPositionsDetail(symbol=self.symble)
        if total is None or len(total) == 0:
            return

        moveSp = False
        for item in total:
            priceOpen = item.price_open
            orderType = item.type
            profit = item.profit
            stopLoss = item.sl
            takeProfit = item.tp
            volume = item.volume
            ticket = item.ticket
            moveSpace = config.getMoveSpace()
            moveProfit = config.getMoveProfit()

            slPrice = 0
            moveValue = 1
            profitSpace = volume * 100 * moveSpace

            # 盈利达到移动止损限定间距值
            if profit > profitSpace:
                # 盈利为两倍间距时，止损值加一个标准单位
                if profit / profitSpace >= 2:
                    moveValue = int(
                        profit / profitSpace) * moveSpace - moveProfit

                if orderType == 0:
                    slPrice = priceOpen + moveValue
                    if stopLoss != 0 and slPrice <= stopLoss:
                        return
                    self.control.changeOrder(item, slPrice, takeProfit)
                    moveSp = True
                elif orderType == 1:
                    slPrice = priceOpen - moveValue
                    if stopLoss != 0 and slPrice >= stopLoss:
                        return
                    self.control.changeOrder(item, slPrice, takeProfit)
                    moveSp = True

        if moveSp is True:
            saveLog("移动止损完成")
            sendMail("移动止损完成")

    def toTargetClose(self):
        """
        15分钟周期,价格跌破30分钟均线时,止损止盈
        且当前区间内禁止下单
        """

        total = self.fibBackClose()
        if total is None or len(total) == 0:
            return

        closeArr = []
        result = self.getKLine(self.symble, 100, mt5.TIMEFRAME_M15)["value"]
        for item in result:
            closeArr.append(item[4])

        maValue = self.indicator.latestMaValue(closeArr, 30)

        latest = result[-1]
        # 前一根k线在30分钟均线下方，且是阴线，关闭所有多单
        if maValue - latest[1] > self.goldPriceOffset / 2 and latest[
                1] - latest[4] - self.goldPriceOffset:
            count = 0
            for item in total:
                # 只处理信号单
                if signalTag in item.comment and item.type == self.POSITION_TYPE_BUY:
                    count = count + 1
                    self.control.closeOrder(item)
            if count != 0:
                saveLog("k线在30日均线下方, 关闭所有多单")
                sendMail("k线在30日均线下方, 关闭所有多单")
        # 前一根k线在30分钟均线上方，且是阳线，关闭所有空单
        elif latest[1] - maValue > self.goldPriceOffset / 2 and latest[
                4] - latest[1] > self.goldPriceOffset:
            count = 0
            for item in total:
                # 只处理信号单
                if signalTag in item.comment and item.type == self.POSITION_TYPE_SELL:
                    count = count + 1
                    self.control.closeOrder(item)
            if count != 0:
                saveLog("k线在30日均线上方, 关闭所有空单")
                sendMail("k线在30日均线上方, 关闭所有空单")

    def fibBackClose(self):
        """
        斐波那契回调止损
        """

        total = self.getPositionsDetail(symbol=self.symble)
        if total is not None and len(total) != 0:
            if fibList2 is not None and len(fibList2) != 0:
                for item in total:
                    for fibIndex in range(0, len(fibList2)):
                        # 多单
                        if item.type == 0 and item.price_open > fibList2[
                                fibIndex]:
                            if fibIndex != len(fibList2) - 1:
                                if item.price_current < fibList2[fibIndex + 1]:
                                    if self.lossMoney():
                                        print("当前价格回调到上一阻力位，已关闭所有多单")
                                        return self.closeAllOrder(total, 0)
                        # 空单
                        elif item.type == 1:
                            fibValue = sorted(fibList2, reverse=False)
                            if item.price_open < fibValue[fibIndex]:
                                if fibIndex != len(fibValue) - 1:
                                    if item.price_current > fibValue[fibIndex +
                                                                     1]:
                                        if self.lossMoney():
                                            print("当前价格回调到上一阻力位，已关闭所有空单")
                                            return self.closeAllOrder(total, 1)
        return total

    def closeAllOrder(self, allOrder, orderType):
        closeList = [item for item in allOrder if item.type == orderType]
        if closeList is not None and len(closeList) != 0:
            for item in closeList:
                self.closeOrder(item, "回调止损")
        return [item for item in allOrder if item.type != orderType]

    def lossMoney(self):
        """
        亏损金额
        """
        info = self.getAccountInfo()
        if info is not None:
            if info.equity < 0 and info.balance > 10:
                if info.equity / info.balance < 0.4:
                    return True
            else:
                return False
        return True

    def tagerClose(self):
        """
        订单关闭
        """

        orderList = self.getPositionsDetail(symbol=self.symble)
        if orderList is None or len(orderList) == 0:
            return

        close = False
        for order in orderList:
            if order.profit > order.volume * 100 * 0.1:
                # 信号单达到阻力位时平仓
                if signalTag in order.comment:
                    orderType = None
                    currentPrice = 0
                    if order.type == 1:
                        orderType = Order.CREATE_SELL
                        currentPrice = self.control.getCurrentPrice(
                            self.symble, orderType=Order.CREATE_SELL)
                    else:
                        orderType = Order.CREATE_BUY
                        currentPrice = self.control.getCurrentPrice(
                            self.symble, orderType=Order.CREATE_BUY)

                    if orderType != None and currentPrice != 0:
                        # 斐波那契阻力位
                        if self.fibFilter(currentPrice):
                            self.control.closeOrder(order)
                            close = True
                        elif self.passRound(orderType, currentPrice):
                            self.control.closeOrder(order)
                            close = True
                # 回调单达到阻力位时平仓
                elif callbackTag in order.comment:
                    if self.backOrderLevel(order.type):
                        self.control.closeOrder(order)
                        close = True
        if close is True:
            saveLog("订单价格已到达阻力位，进行关闭订单操作")
            return

        # 完成日内盈利目标
        if self.getPlanState() is False:
            for order in orderList:
                # 信号单附加单关闭操作
                if signalTag in order.comment and "附加单" in order.comment:
                    if order.profit > order.volume * 100 * 0.5:
                        # self.control.closeOrder(order)
                        close = False
                # 回调单关闭操作
                elif signalTag in order.comment or callbackTag in order.comment:
                    if order.profit > order.volume * 100 * 0.1:
                        self.control.closeOrder(order)
                        close = True
        if close is True:
            # profitStr = "日内总盈利为" + str(int(allProfit)) + "美金"
            profitMsg = "总盈利达到日内目标值，已关闭所有订单"

            sendMail(profitMsg, msg=profitMsg, timer=False)
            saveLog(profitMsg)
        return

    def addOrder(self):
        """
        加仓
        处理数据单、回调单、现价单
        """

        if config.getAddOrderStatus() is False:
            return

        # 当前有持仓时加仓
        total = self.getPositionsDetail(symbol=self.symble)
        if total is not None and len(total) != 0:
            orders = [item for item in total if immediatelyTag in item.comment]
            if len(orders) != 0:
                # 最新成交单
                lasterOrder = max(orders, key=lambda item: item.time)
                if lasterOrder.profit > 0:
                    self.createOrder(lasterOrder.type, lasterOrder.price_open)
        else:
            # 下单前检查，是否达到日内目标盈利和是否有重要事件发布
            # if self.createOrderCheck(self.printLog, "加仓服务") is False:
            #     self.printLog = True
            #     return
            # self.printLog = False

            # 当前没有持仓时加仓
            total = self.dayAllOrder()
            if total is not None and len(total) != 0:
                comment = total[-1]["comment"]
                if immediatelyTag in comment:
                    profit = total[-1]["profit"]
                    closePrice = total[-1]["close_price"]
                    openPrice = total[-1]["open_price"]
                    if profit > 0:
                        self.createOrder(total[-1]["type"], closePrice)

    def createOrder(self, orderType, orderPrice):
        """
        订单加仓
        """

        buyPrice = self.control.getCurrentPrice(self.symble,
                                                orderType=Order.CREATE_BUY)
        sellPrice = self.control.getCurrentPrice(self.symble,
                                                 orderType=Order.CREATE_SELL)

        if orderType == 1 and orderPrice - sellPrice > self.goldPriceOffset + 1:
            tp = self.getStrategyTp(Order.CREATE_SELL)
            if sellPrice - tp > self.goldPriceOffset + 1:
                self.control.createOrder(OrderType.SELL,
                                         self.symble,
                                         priceSp=sellPrice + 2,
                                         remark=immediatelyTag + "_加仓")
        elif orderType == 0 and buyPrice - orderPrice > self.goldPriceOffset + 1:
            tp = self.getStrategyTp(Order.CREATE_BUY)
            if tp - buyPrice > self.goldPriceOffset + 1:
                self.control.createOrder(OrderType.BUY,
                                         self.symble,
                                         priceSp=buyPrice - 2,
                                         remark=immediatelyTag + "_加仓")
